﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.Workflow.ComponentModel;
using System.Configuration;
using System.Collections;
using System.Diagnostics;
using TextFlow.Activities;

namespace TextFlow.Engine
{
    internal static class ActivityFactory
    {
        private static int _counter = int.MinValue;

        private static Dictionary<string, Type> _actions = null;

        static ActivityFactory()
        {
            _actions = new Dictionary<string, Type>();

            Hashtable fromConfig = ConfigurationManager.GetSection( "TextFlowActions" ) as Hashtable;

            foreach ( string key in fromConfig.Keys.Cast<string>() )
            {
                string typeName = (string) fromConfig[ key ];

                Debug.Assert( string.IsNullOrEmpty( typeName ) == false );

                Type t = Type.GetType( typeName );

                if ( t.IsSubclassOf( typeof( Activity ) ) == false )
                {
                    throw new InvalidOperationException( string.Format( "{0} config entry does not resolve to a WF activity type.", key ) );
                }

                if ( _actions.ContainsValue( t ) )
                {
                    throw new InvalidOperationException( string.Format( "Duplicate config entry for activity type: {0}", t.AssemblyQualifiedName ) );
                }
                else
                {
                    _actions.Add( key, t );
                }
            }
        }

        public static void Init()
        {
            _counter = 1;
        }

        public static T Create<T>() where T : Activity
        {
            T activity = Activator.CreateInstance<T>();

            activity.Name = string.Format( "{0}{1}", typeof( T ).Name, _counter++ );

            return activity;
        }

        public static Activity Create( string identifier )
        {
            if ( _actions.ContainsKey( identifier ) )
            {
                Type t = _actions[ identifier ];

                Activity activity = Activator.CreateInstance( t ) as Activity;

                Debug.Assert( activity != null );

                activity.Name = string.Format( "{0}{1}", activity.GetType().Name, _counter++ );

                return activity;
            }
            else
            {
                throw new InvalidOperationException( string.Format( "Action [{0}] not configured.", identifier ) );
            }
        }

        public static ActionInputActivity CreateInputActivity( string boundPropName, Type boundPropType )
        {
            return DynamicActivityGenerator.CreateInputActivity( boundPropName, boundPropType, string.Format( "ActionInput{0}", _counter++ ) );
        }

        public static ActionOutputActivity CreateOutputActivity( string boundPropName, Type boundPropType )
        {
            return DynamicActivityGenerator.CreateOutputActivity( boundPropName, boundPropType, string.Format( "ActionOutput{0}", _counter++ ) );
        }

        public static string GetIdentifier( Type t )
        {
            var result = from pair in _actions where pair.Value == t select pair.Key;

            if ( result.Count() > 0 )
            {
                return result.First();
            }
            else
            {
                throw new InvalidOperationException( string.Format( "Type {0} not mapped to identifier.", t.AssemblyQualifiedName ) );
            }
        }
    }
}
